package com.boilermaker.lotterysystem.service.async.impl;

import com.boilermaker.lotterysystem.common.errorcode.ServiceErrorCodeConstants;
import com.boilermaker.lotterysystem.common.exception.ServiceException;
import com.boilermaker.lotterysystem.service.async.AsyncTaskExecutorService;
import com.boilermaker.lotterysystem.service.async.asynctask.AsyncTask;
import com.boilermaker.lotterysystem.service.async.retry.RetryPolicy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class AsyncTaskExecutorServiceImpl implements AsyncTaskExecutorService {

    @Autowired
    private ThreadPoolTaskExecutor asyncServiceExecutor;

    private final Map<String, AsyncTask<?>> asyncTaskMap;

    @Autowired // 构造器注入
    public AsyncTaskExecutorServiceImpl(Map<String, AsyncTask<?>> asyncTaskMap) {
        this.asyncTaskMap = asyncTaskMap;
    }

    /**
     * 提交任务到线程池
     *
     * @param taskName 默认 Bean 名，如 emailNotificationTask
     * @param dto 执行该任务所需的参数
     * @return 该异步任务执行的状态
     */
    @Override
    public <T> CompletableFuture<Void> submitTask(String taskName, T dto) {

        @SuppressWarnings("unchecked") // 抑制泛型相关的未经检查转换警告
        AsyncTask<T> asyncTask = (AsyncTask<T>) asyncTaskMap.get(taskName);

        if (asyncTask == null) {
            log.warn("未知的任务类型:{} ", taskName);
            return CompletableFuture.failedFuture(
                    new ServiceException(ServiceErrorCodeConstants.SUBMIT_ASYNC_TASK_ERROR));
        }

        return CompletableFuture.runAsync(() -> executeWithRetry(asyncTask, dto),
                asyncServiceExecutor);
    }

    /**
     * 带重试的任务执行
     */
    private <T> void executeWithRetry(AsyncTask<T> asyncTask, T dto) {

        RetryPolicy retryPolicy = asyncTask.getRetryPolicy();

        for (int attempt = 1; attempt <= retryPolicy.getMaxAttempts(); attempt++) {
            try {
                asyncTask.validate(dto);
                asyncTask.execute(dto);
                asyncTask.onComplete(dto, true);
                return;
            } catch (Exception e) {
                log.warn("任务执行失败 [类型: {}, 尝试: {}/{}]",
                        asyncTask.getTaskType(), attempt, retryPolicy.getMaxAttempts(), e);

                // 退避等待，避免立即重试
                if (attempt < retryPolicy.getMaxAttempts()) {
                    try {
                        // 等待时间随重试次数增加而增加
                        Thread.sleep(retryPolicy.getBackoffDelayMs() * attempt);
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }

        asyncTask.onComplete(dto, false);
    }
}
